package Inherit.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Scanner;

public class ReflectionTest {
    public static void main(String[] args){
        //read class name from command line args or user input
        String name;
        if(args.length>0) name=args[0];
        else {
            Scanner in=new Scanner(System.in);
            System.out.println("Enter class name(e.g. java.util.Data): ");
            name=in.next();
        }
        try {
            //print class name and superclass name (if!=Object)
            Class cl=Class.forName(name);
            Class supercl=cl.getSuperclass();
            String modifiers= Modifier.toString(cl.getModifiers());
            if(modifiers.length()>0) System.out.print(modifiers+"  ");
            System.out.print("class "+name);
            if(supercl!=null&&supercl!=Object.class)
                System.out.println("  extends "+supercl.getName());

            System.out.print("\n{\n");
            printConstructor(cl);
            System.out.println();
            printMethods(cl);
            System.out.println();
            printFields(cl);
            System.out.println("}");
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        }

        System.exit(0);
    }

    /**
     * Prints all fields of class
     * @param cl a class
     */
    private static void printFields(Class cl) {
        Field[] fields=cl.getDeclaredFields();

        for(Field field:fields){
            Class type=field.getType();
            String name=field.getName();
            System.out.print("   ");
            String modifiers=Modifier.toString(field.getModifiers());
            if(modifiers.length()>0)
                System.out.print(modifiers+" ");
            System.out.println(type.getName()+" "+name+";");
        }
    }

    /**
     * Print all methods of a class
     * @param cl a class
     */
    private static void printMethods(Class cl) {
        Method[] methods=cl.getDeclaredMethods();

        for(Method method:methods){
            Class returnType=method.getReturnType();
            String name=method.getName();

            System.out.print("  ");
            //print modifiers,return type and method name
            String modifiers=Modifier.toString(method.getModifiers());
            if(modifiers.length()>0)
                System.out.print(modifiers+"  ");
            System.out.print(returnType.getName()+" "+name+" (");

            //print parameter types
            Class[] paramTypes=method.getParameterTypes();
            for(int j=0;j<paramTypes.length;j++){
                if(j>0) System.out.print(", ");
                System.out.print(paramTypes[j].getName());
            }
            System.out.println(");");
        }
    }

    /**
     * Print constructors of a class
     * @param cl a class
     */
    private static void printConstructor(Class cl) {
        Constructor[] constructors=cl.getConstructors();
        for(Constructor constructor:constructors){
            String name=constructor.getName();
            System.out.print("  ");
            String modifiers=Modifier.toString(constructor.getModifiers());
            if(modifiers.length()>0)
                System.out.print(modifiers+"  ");
            System.out.print(name+"(");

            Class[] paramTypes=constructor.getParameterTypes();
            for (int j=0;j<paramTypes.length;j++){
                if(j>0) System.out.print(", ");
                System.out.print(paramTypes[j].getName());
            }
            System.out.println(");");
        }
    }
}
